import {
  ChatCompletionContentPart,
  ChatCompletionFunctionMessageParam,
  ChatCompletionMessageFunctionCall,
  ChatCompletionMessageParam,
  ChatCompletionMessageToolCall,
  ChatCompletionToolMessageParam,
} from '@/pages/chat/tools/constants';
import { ChatCompletionRequestMessageRoleEnum } from '@/types/ai/constants';
import { ChatFileTypeEnum, ChatItemValueTypeEnum, ChatRoleEnum } from '@/types/chat/constants';
import {
  ChatItemType,
  ChatItemValueItemType,
  RuntimeUserPromptType,
  UserChatItemType,
} from '@/types/chat/type';

const GPT2Chat = {
  [ChatCompletionRequestMessageRoleEnum.System]: ChatRoleEnum.System,
  [ChatCompletionRequestMessageRoleEnum.User]: ChatRoleEnum.Human,
  [ChatCompletionRequestMessageRoleEnum.Assistant]: ChatRoleEnum.AI,
  [ChatCompletionRequestMessageRoleEnum.Function]: ChatRoleEnum.AI,
  [ChatCompletionRequestMessageRoleEnum.Tool]: ChatRoleEnum.AI,
};

export function adaptRole_Message2Chat(role: `${ChatCompletionRequestMessageRoleEnum}`) {
  return GPT2Chat[role];
}

export const simpleUserContentPart = (content: ChatCompletionContentPart[]) => {
  if (content.length === 1 && content[0].type === 'text') {
    return content[0].text;
  }
  return content;
};

export const chats2GPTMessages = ({
  messages,
  reserveId,
  reserveTool = false,
}: {
  messages: ChatItemType[];
  reserveId: boolean;
  reserveTool?: boolean;
}): ChatCompletionMessageParam[] => {
  let results: ChatCompletionMessageParam[] = [];

  messages.forEach((item) => {
    const dataId = reserveId ? item.dataId : undefined;
    if (item.obj === ChatRoleEnum.Human) {
      const value = item.value
        .map((item) => {
          if (item.type === ChatItemValueTypeEnum.text) {
            return {
              type: 'text',
              text: item.text?.content || '',
            };
          }
          if (item.type === ChatItemValueTypeEnum.file) {
            if (item.file?.type === ChatFileTypeEnum.image) {
              return {
                type: 'image_url',
                image_url: {
                  url: item.file?.url || '',
                },
              };
            }
            if (item.file?.type === ChatFileTypeEnum.file) {
              return {
                type: 'file_url',
                name: item.file?.name || '',
                url: item.file?.url || '',
              };
            }
          }
        })
        .filter(Boolean) as ChatCompletionContentPart[];

      results.push({
        dataId,
        role: ChatCompletionRequestMessageRoleEnum.User,
        content: simpleUserContentPart(value) ?? '',
      });
    } else if (item.obj === ChatRoleEnum.System) {
      const content = item.value?.[0]?.text?.content;
      if (content) {
        results.push({
          dataId,
          role: ChatCompletionRequestMessageRoleEnum.System,
          content,
        });
      }
    } else {
      const aiResults: ChatCompletionMessageParam[] = [];
      // AI
      item.value.forEach((value, i) => {
        if (value.type === ChatItemValueTypeEnum.tool && value.tools && reserveTool) {
          const tool_calls: ChatCompletionMessageToolCall[] = [];
          const toolResponse: ChatCompletionToolMessageParam[] = [];
          value.tools.forEach((tool) => {
            tool_calls.push({
              id: tool.id,
              type: 'function',
              function: {
                name: tool.functionName,
                arguments: tool.params,
              },
            });
            toolResponse.push({
              tool_call_id: tool.id,
              role: ChatCompletionRequestMessageRoleEnum.Tool,
              name: tool.functionName,
              content: tool.response,
            });
          });
          aiResults.push({
            dataId,
            role: ChatCompletionRequestMessageRoleEnum.Assistant,
            tool_calls,
          });
          // aiResults.push(...toolResponse);
        } else if (
          value.type === ChatItemValueTypeEnum.text &&
          typeof value.text?.content === 'string'
        ) {
          if (!value.text.content && item.value.length > 1) {
            return;
          }
          // Concat text
          const lastValue = item.value[i - 1];
          const lastResult = aiResults[aiResults.length - 1];
          if (
            lastValue &&
            lastValue.type === ChatItemValueTypeEnum.text &&
            typeof lastResult.content === 'string'
          ) {
            lastResult.content += value.text.content;
          } else {
            aiResults.push({
              dataId,
              role: ChatCompletionRequestMessageRoleEnum.Assistant,
              content: value.text.content,
            });
          }
        } else if (value.type === ChatItemValueTypeEnum.interactive) {
          aiResults.push({
            dataId,
            role: ChatCompletionRequestMessageRoleEnum.Assistant,
            interactive: value.interactive,
          });
        }
      });

      // Auto add empty assistant message
      results = results.concat(
        aiResults.length > 0
          ? aiResults
          : [
              {
                dataId,
                role: ChatCompletionRequestMessageRoleEnum.Assistant,
                content: '',
              },
            ],
      );
    }
  });

  return results;
};
export const GPTMessages2Chats = (
  messages: ChatCompletionMessageParam[],
  reserveTool = true,
): ChatItemType[] => {
  const chatMessages = messages
    .map((item) => {
      const value: ChatItemType['value'] = [];
      const obj = GPT2Chat[item.role];

      if (
        obj === ChatRoleEnum.System &&
        item.role === ChatCompletionRequestMessageRoleEnum.System
      ) {
        if (Array.isArray(item.content)) {
          item.content.forEach((item) => [
            value.push({
              type: ChatItemValueTypeEnum.text,
              text: {
                content: item.text,
              },
            }),
          ]);
        } else {
          value.push({
            type: ChatItemValueTypeEnum.text,
            text: {
              content: item.content,
            },
          });
        }
      } else if (
        obj === ChatRoleEnum.Human &&
        item.role === ChatCompletionRequestMessageRoleEnum.User
      ) {
        if (typeof item.content === 'string') {
          value.push({
            type: ChatItemValueTypeEnum.text,
            text: {
              content: item.content,
            },
          });
        } else if (Array.isArray(item.content)) {
          item.content.forEach((item) => {
            if (item.type === 'text') {
              value.push({
                type: ChatItemValueTypeEnum.text,
                text: {
                  content: item.text,
                },
              });
            } else if (item.type === 'image_url') {
              value.push({
                // @ts-ignore
                type: ChatItemValueTypeEnum.file,
                file: {
                  type: ChatFileTypeEnum.image,
                  name: '',
                  url: item.image_url.url,
                },
              });
            } else if (item.type === 'file_url') {
              value.push({
                // @ts-ignore
                type: ChatItemValueTypeEnum.file,
                file: {
                  type: ChatFileTypeEnum.file,
                  name: item.name,
                  url: item.url,
                },
              });
            }
          });
        }
      } else if (
        obj === ChatRoleEnum.AI &&
        item.role === ChatCompletionRequestMessageRoleEnum.Assistant
      ) {
        if (item.tool_calls && reserveTool) {
          // save tool calls
          const toolCalls = item.tool_calls as ChatCompletionMessageToolCall[];
          value.push({
            // @ts-ignore
            type: ChatItemValueTypeEnum.tool,
            tools: toolCalls.map((tool) => {
              let toolResponse =
                messages.find(
                  (msg) =>
                    msg.role === ChatCompletionRequestMessageRoleEnum.Tool &&
                    msg.tool_call_id === tool.id,
                )?.content || '';
              toolResponse =
                typeof toolResponse === 'string' ? toolResponse : JSON.stringify(toolResponse);

              return {
                id: tool.id,
                toolName: tool.toolName || '',
                toolAvatar: tool.toolAvatar || '',
                functionName: tool.function.name,
                params: tool.function.arguments,
                response: toolResponse as string,
              };
            }),
          });
        } else if (item.function_call && reserveTool) {
          const functionCall = item.function_call as ChatCompletionMessageFunctionCall;
          const functionResponse = messages.find(
            (msg) =>
              msg.role === ChatCompletionRequestMessageRoleEnum.Function &&
              msg.name === item.function_call?.name,
          ) as ChatCompletionFunctionMessageParam;

          if (functionResponse) {
            value.push({
              // @ts-ignore
              type: ChatItemValueTypeEnum.tool,
              tools: [
                {
                  id: functionCall.id || '',
                  toolName: functionCall.toolName || '',
                  toolAvatar: functionCall.toolAvatar || '',
                  functionName: functionCall.name,
                  params: functionCall.arguments,
                  response: functionResponse.content || '',
                },
              ],
            });
          }
        } else if (item.interactive) {
          value.push({
            // @ts-ignore
            type: ChatItemValueTypeEnum.interactive,
            interactive: item.interactive,
          });
        } else if (typeof item.content === 'string') {
          const lastValue = value[value.length - 1];
          if (lastValue && lastValue.type === ChatItemValueTypeEnum.text && lastValue.text) {
            lastValue.text.content += item.content;
          } else {
            value.push({
              type: ChatItemValueTypeEnum.text,
              text: {
                content: item.content,
              },
            });
          }
        }
      }

      return {
        dataId: item.dataId,
        obj,
        value,
      } as ChatItemType;
    })
    .filter((item) => item.value.length > 0);

  // Merge data with the same dataId（Sequential obj merging）
  const result = chatMessages.reduce((result: ChatItemType[], currentItem) => {
    const lastItem = result[result.length - 1];

    if (lastItem && lastItem.dataId === currentItem.dataId && lastItem.obj === currentItem.obj) {
      // @ts-ignore
      lastItem.value = lastItem.value.concat(currentItem.value);
    } else {
      result.push(currentItem);
    }

    return result;
  }, []);

  return result;
};

export const chatValue2RuntimePrompt = (value: ChatItemValueItemType[]): RuntimeUserPromptType => {
  const prompt: RuntimeUserPromptType = {
    files: [],
    text: '',
  };
  value.forEach((item) => {
    if (item.type === 'file' && item.file) {
      prompt.files?.push(item.file);
    } else if (item.text) {
      prompt.text += item.text.content;
    }
  });
  return prompt;
};

export const runtimePrompt2ChatsValue = (
  prompt: RuntimeUserPromptType,
): UserChatItemType['value'] => {
  const value: UserChatItemType['value'] = [];
  if (prompt.files) {
    prompt.files.forEach((file) => {
      value.push({
        type: ChatItemValueTypeEnum.file,
        file,
      });
    });
  }
  if (prompt.text) {
    value.push({
      type: ChatItemValueTypeEnum.text,
      text: {
        content: prompt.text,
      },
    });
  }
  return value;
};

export const getSystemPrompt_ChatItemType = (prompt?: string): ChatItemType[] => {
  if (!prompt) return [];
  return [
    {
      obj: ChatRoleEnum.System,
      value: [{ type: ChatItemValueTypeEnum.text, text: { content: prompt } }],
    },
  ];
};
